﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using Microsoft.SharePoint;

using System.Net;
using System.Web;
using System.IO;
using System.Security.Principal;

namespace Microsoft.PKS
{
	public static class GfxUtils
	{
		/// <summary>
		/// Allows drawing fonts with borders and auto centers the font on a bitmap.
		/// </summary>
		public class PowerFont
		{
			private Font font;
			private Brush tc, oc;

			public PowerFont(string fontName, float fontSize, Color textColor, Color outlineColor, string style)
			{
				if (string.IsNullOrEmpty(fontName)) { fontName = "Arial"; }
				if (fontSize <= 0) { fontSize = 10; }

				FontStyle fs = FontStyle.Regular;
				if (!string.IsNullOrEmpty(style))
				{
					style = style.ToLower();
					if (style.Contains("bold")) { fs |= FontStyle.Bold; }
					if (style.Contains("italic")) { fs |= FontStyle.Italic; }
					if (style.Contains("strike")) { fs |= FontStyle.Strikeout; }
					if (style.Contains("underline")) { fs |= FontStyle.Underline; }
				}

				font = new Font(fontName, fontSize, fs);
				tc = new SolidBrush(textColor);
				oc = new SolidBrush(outlineColor);
			}

			public void WriteText(Bitmap img, string text)
			{
				Graphics g = Graphics.FromImage(img);
				g.PageUnit = GraphicsUnit.Pixel;

				SizeF sz = g.MeasureString(text, font, new SizeF(img.Width, img.Height));

				float x, y;
				x = (img.Width / 2) - (sz.Width / 2);
				y = (img.Height / 2) - (sz.Height / 2);

				float offset = font.Size / 10;

				StringFormat sf = new StringFormat();
				sf.Alignment = StringAlignment.Center;

				RectangleF loc = RectangleF.Empty;

				//draw border
				for (float ox = -(offset); ox <= offset; ox++)
				{
					for (float oy = -(offset); oy <= offset; oy++)
					{
						loc = new RectangleF(x + ox, y + oy, sz.Width, sz.Height);
						g.DrawString(text, font, oc, loc, sf);
					}
				}

				loc = new RectangleF(x, y, sz.Width, sz.Height);

				//draw text
				g.DrawString(text, font, tc, loc, sf);
				
				g.Flush(FlushIntention.Flush);
			}
		}

		/// <summary>
		/// Converts any bitmap (event paletted ones) to 32 bit argb so that we can draw on them.
		/// </summary>
		/// <param name="bmp"></param>
		/// <returns></returns>
		public static Bitmap ConvertBitmapToArgb(Bitmap bmp)
		{
			if (bmp.PixelFormat == PixelFormat.Format32bppArgb) { return bmp; }

			Bitmap output = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppArgb);
			Graphics g = Graphics.FromImage(output);
			g.CompositingQuality = CompositingQuality.HighQuality;
			g.CompositingMode = CompositingMode.SourceCopy;
			g.InterpolationMode = InterpolationMode.HighQualityBicubic;
			g.PageUnit = GraphicsUnit.Pixel;
			g.SmoothingMode = SmoothingMode.HighQuality;

			g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
			g.Flush(FlushIntention.Flush);
			return output;
		}

		/// <summary>
		/// Loads a bitmap given a URI, currently supports file system, asp virtual paths, and http, soon to be added: sharepoint list
		/// </summary>
		/// <param name="location"></param>
		/// <param name="web"></param>
		/// <returns></returns>
		public static Bitmap LoadBitmap(string location, SPWeb web)
		{
			if (string.IsNullOrEmpty(location)) { return null; }

			try
			{
				Bitmap bmp = new Bitmap(location);
				return ConvertBitmapToArgb(bmp);
			}
			catch { }

			//todo, check if sharepoint can open the image, (ie, pass in an SPWeb (nullable))
			if (web != null)
			{


			}

			try
			{
				Bitmap bmp = new Bitmap(HttpContext.Current.Server.MapPath(location));
				return ConvertBitmapToArgb(bmp);
			}
			catch { }

			try
			{
				HttpWebRequest req = (HttpWebRequest)WebRequest.Create(location);
				HttpWebResponse resp = (HttpWebResponse)req.GetResponse();

				Stream str = resp.GetResponseStream();
				Bitmap bmp = new Bitmap(str);
				str.Close();
				str.Dispose();

				return ConvertBitmapToArgb(bmp);
			}
			catch (WebException webEx)
			{
				if (webEx.Status == WebExceptionStatus.ProtocolError)
				{
					try
					{
						HttpWebRequest req = (HttpWebRequest)WebRequest.Create(location);
						req.Credentials = CredentialCache.DefaultNetworkCredentials;
						HttpWebResponse resp = (HttpWebResponse)req.GetResponse();

						Stream str = resp.GetResponseStream();
						Bitmap bmp = new Bitmap(str);
						str.Close();
						str.Dispose();

						return ConvertBitmapToArgb(bmp);
					}
					catch { }
				}
			}
			catch { }

			return null;
		}


		public static class HighQualityBitmapResizer
		{

			/// <summary>
			/// Resizes a System.Drawing.Bitmap.
			/// </summary>
			/// <param name="input">The bitmap to resize.</param>
			/// <param name="targetSize">The target size.</param>
			/// <returns>The resized bitmap.</returns>
			public static Bitmap ResizeBitmap(Bitmap input, Size targetSize)
			{
				return ResizeBitmap(input, targetSize, false, Color.Black);
			}

			/// <summary>
			/// Resizes a System.Drawing.Bitmap.
			/// </summary>
			/// <param name="input">The bitmap to resize.</param>
			/// <param name="targetSize">The target size.</param>
			/// <param name="allowDistortion">Should the resize routine allow distortion?</param>
			/// <returns>The resized bitmap.</returns>
			public static Bitmap ResizeBitmap(Bitmap input, Size targetSize, bool allowDistortion)
			{
				return ResizeBitmap(input, targetSize, allowDistortion, Color.Black);
			}

			/// <summary>
			/// Resizes a System.Drawing.Bitmap.
			/// </summary>
			/// <param name="input">The bitmap to resize.</param>
			/// <param name="targetSize">The target size.</param>
			/// <param name="allowDistortion">Should the resize routine allow distortion?</param>
			/// <param name="backgroundColor">The color of the bars on to put on the sides when preventing distortion.</param>
			/// <returns>The resized bitmap.</returns>
			public static Bitmap ResizeBitmap(Bitmap input, Size targetSize, bool allowDistortion, Color backgroundColor)
			{
				if (input == null) { throw new ArgumentNullException("input"); }
				if (targetSize == Size.Empty || targetSize.Width < 1 || targetSize.Height < 1)
				{ throw new ArgumentOutOfRangeException("targetSize", "targetSize must be 1x1 or larger."); }

				//if (input.Size == targetSize) { return (Bitmap)input.Clone(); } //recreate the image as a 32 bit argb no matter what.

				double sx, sy, cw, ch, nw, nh;
				cw = (double)input.Width;
				ch = (double)input.Height;

				if (allowDistortion)
				{
					nw = targetSize.Width;
					nh = targetSize.Height;
				}
				else
				{
					nw = (double)targetSize.Width;
					nh = (nw / cw) * ch;

					if (nh > targetSize.Height)
					{
						nh = (double)targetSize.Height;
						nw = (nh / ch) * cw;
					}
				}

				Bitmap output = new Bitmap(targetSize.Width, targetSize.Height, PixelFormat.Format32bppArgb);
				Graphics g = Graphics.FromImage(output);
				g.CompositingQuality = CompositingQuality.HighQuality;
				g.CompositingMode = CompositingMode.SourceCopy;
				g.InterpolationMode = InterpolationMode.HighQualityBicubic;
				g.PageUnit = GraphicsUnit.Pixel;
				g.SmoothingMode = SmoothingMode.HighQuality;

				sx = (targetSize.Width / 2) - (nw / 2);
				sy = (targetSize.Height / 2) - (nh / 2);
				Rectangle rect = new Rectangle((int)sx, (int)sy, (int)nw, (int)nh);

				g.Clear(backgroundColor);
				g.DrawImage(input, rect);

				g.Flush(FlushIntention.Flush);

				return output;
			}
		}
	}
}
